package cn.easyar.samples.helloarcustomcamera.utils;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.media.Image;
import android.media.ImageReader;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.Buffer;

import cn.easyar.samples.helloarcustomcamera.AppCore;

public class YuvToFile {

    private final static String TAG = "YuvToFile";

    public static String tackPhoto(ImageReader reader){
        if (ImageFormat.YUV_420_888 == reader.getImageFormat()) {
            return getBitmapFromYuvReader(reader);
        }else {
            return "";
        }
    }


    //从ImageReader中读取yuv并转成bitmap
    private static synchronized String getBitmapFromYuvReader(ImageReader reader) {
        if (null == reader) {
            Log.i(TAG, "getBitmapFromYuvReader() reader is null return null");
            return null;
        }

        Image image = null;
        try {
            byte[] plane0Y = null;
            byte[] plane1WithU = null; //plane1 包含u
            byte[] plane2WithV = null; //plane2 包含v
            byte[] u = null;//真实的u
            byte[] v = null;//真实的u
// fos = new FileOutputStream(file);
//获取捕获的照片数据
            image = reader.acquireLatestImage();
            if (null == image) {
                Log.w(TAG, "getBitmapFromYuvReader() image is null");
                return null;
            }
            Image.Plane[] planes = image.getPlanes();
            Log.i(TAG, "getBitmapFromYuvReader() planes.length:" + planes.length);
            if (planes.length != 3) {
                return null;
            }
// 重复使用同一批byte数组，减少gc频率
            if (plane0Y == null || plane1WithU == null || plane2WithV == null) {
                plane0Y = new byte[planes[0].getBuffer().limit() - planes[0].getBuffer().position()];
                plane1WithU = new byte[planes[1].getBuffer().limit() - planes[1].getBuffer().position()];
                plane2WithV = new byte[planes[2].getBuffer().limit() - planes[2].getBuffer().position()];
            }
            for (int i = 0; i < planes.length; i++) {
                Image.Plane plane = planes[i];
                Buffer buffer = plane.getBuffer();
//1280*720
                Log.i(TAG, "getBitmapFromYuvReader() i:" + i + " buffer.remaining:" + buffer.remaining()
                        + " getPixelStride:" + plane.getPixelStride() + " getRowStride:" + plane.getRowStride());
            }
            if (image.getPlanes()[0].getBuffer().remaining() == plane0Y.length) {
                planes[0].getBuffer().get(plane0Y);
                planes[1].getBuffer().get(plane1WithU);
                planes[2].getBuffer().get(plane2WithV);
                if (planes[1].getPixelStride() == 2) { //sp
//提取U v分量 ，这里需要+1，因为plane1和plane2都是少存储一个字节
                    u = new byte[(plane1WithU.length + 1) / 2];
                    v = new byte[(plane2WithV.length + 1) / 2];
                    int index_u = 0;
                    int index_v = 0;
                    for (int i = 0; i < plane1WithU.length; i++) {
                        if (0 == (i % 2)) {
                            u[index_u] = plane1WithU[i];
                            index_u++;
                        }
                    }
                    for (int j = 0; j < plane2WithV.length; j++) {
                        if (0 == (j % 2)) {
                            v[index_v] = plane2WithV[j];
                            index_v++;
                        }
                    }
                }
                byte[] arrayNV21 = getArrayNV21FromYuv(plane0Y, u, v);
                final int WIDTH = Constant.SHOOT_PIC_WIDTH;
                final int HEIGHT = Constant.SHOOT_PIC_HEIGHT;
                Log.i(TAG, "getBitmapFromYuvReader() arrayNV21.length:" + arrayNV21.length);
                YuvImage yuvImage = new YuvImage(arrayNV21, ImageFormat.NV21, WIDTH, HEIGHT, null);
                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                yuvImage.compressToJpeg(new Rect(0, 0, WIDTH, HEIGHT), 80, stream);

                String path = "";
                try{
                    String jpgFilePath = AppCore.getInstance().getContext().getFilesDir().getAbsolutePath() + "/take_pic.jpg";
                    FileOutputStream output = new FileOutputStream(jpgFilePath);
                    output.write(stream.toByteArray());
                    output.flush();
                    output.close();
                    path = jpgFilePath;
                }catch(FileNotFoundException e){
                    e.printStackTrace();
                }catch(IOException e){
                    e.printStackTrace();
                }

                /*Bitmap newBitmap = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
                stream.close();*/
                return path;
            }

        } catch (Exception ex) {
            Log.i(TAG, "getBitmapFromYuvReader() error:" + ex);
        } finally {

            //记得关闭 image
            if (image != null) {
                image.close();
            }
        }
        return null;
    }
    //将yuv 数据合并成 nv21格式的byte数组
    private static byte[] getArrayNV21FromYuv(byte[] y, byte[] u, byte[] v) {
//正常来说y长度是WIDTH*HEIGHT,u和v的长度是WIDTH*HEIGHT/4
        final int WIDTH = Constant.SHOOT_PIC_WIDTH;//图片宽
        final int HEIGHT = Constant.SHOOT_PIC_HEIGHT;//图片宽
        if (WIDTH * HEIGHT != y.length) {
            Log.i(TAG, "getArrayNV21FromYuv() y length is error");
            return null;
        }
        if ((WIDTH * HEIGHT / 4) != u.length || (WIDTH * HEIGHT / 4) != v.length) {
            Log.i(TAG, "getArrayNV21FromYuv() u or v length is error!");
            return null;
        }
        int lengthY = y.length;
        int lengthU = u.length;
        int lengthV = u.length;
        int newLength = lengthY + lengthU + lengthV;
        byte[] arrayNV21 = new byte[newLength];
//先将所有的Y数据存储进去
        System.arraycopy(y, 0, arrayNV21, 0, y.length);

//然后交替存储VU数据(注意U，V数据的长度应该是相等的，记住顺序是VU VU)
        for (int i = 0; i < v.length; i++) {
            int index = lengthY + i * 2;
            arrayNV21[index] = v[i];
        }

        for (int i = 0; i < u.length; i++) {
            int index = lengthY + i * 2 + 1;
            arrayNV21[index] = u[i];
        }
        Log.i(TAG, "getArrayNV21FromYuv()");
        return arrayNV21;
    }
}
